package com.suning.sawp.service.impl.biz;

import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.suning.sawp.constants.ErrorCodeConstants;
import com.suning.sawp.dto.common.ReturnMsg;
import com.suning.sawp.dto.esb.CasProductPrice;
import com.suning.sawp.dto.esb.ProductMatchBean;
import com.suning.sawp.dto.esb.ProductPriceBean;
import com.suning.sawp.dto.price.ComparePriceResult;
import com.suning.sawp.dto.price.DatePrice;
import com.suning.sawp.dto.price.SiteHistoryPrice;
import com.suning.sawp.dto.price.SiteInfo;
import com.suning.sawp.intf.biz.CasComparePriceService;
import com.suning.sawp.intf.dao.StoreManSubProductDaoService;
import com.suning.sawp.intf.esb.CasGetProductPriceService;
import com.suning.sawp.po.StoreManSubProduct;
import com.suning.sawp.service.util.ConfigUtil;
import com.suning.sawp.service.util.DateUtils;

@Service("casComparePriceService")
public class CasComparePriceServiceImpl implements CasComparePriceService {

    private static final Logger LOGGER = LoggerFactory.getLogger(CasComparePriceServiceImpl.class);
    
    /**
     * 店员关注商品的上限
     */
    private static final int TOTAL_SIZE = 20;
    
    /**
     * CAS接口返回成功有匹配比价信息的成功码
     */
    private static final String CAS_SUCCESS_CODE = "0000";
    
    /***
     * 竞争对手站点名
     */
    private static final Map<String, String> SITES = new HashMap<String, String>();
    static {
        SITES.put("1", "亚马逊");
        SITES.put("2", "当当");
        SITES.put("3", "京东");
        SITES.put("15", "易迅");
        SITES.put("25", "苏宁易购");
        SITES.put("28", "国美");
        SITES.put("31", "1号店");
    }
    
    /**
     * 小数格式
     */
    private static final DecimalFormat DF = new DecimalFormat("#.00");
    
    @Resource
    StoreManSubProductDaoService storeManSubProductDaoService;
    
    @Resource
    CasGetProductPriceService casGetProductPriceService;
    
    @Override
    public ReturnMsg<String> subscribleProduct(String staffId, String productId, String productName) {
        ReturnMsg<String> returnMsg = new ReturnMsg<String>();
        // 先判断该员工所关注的商品数是否已达到上限
        int total = storeManSubProductDaoService.countMySubProducts(staffId, null);
        if (total < TOTAL_SIZE) {
            // 未达到关注上限，判断此productId是否已被关注
            int num = storeManSubProductDaoService.countMySubProducts(staffId, productId);
            if (num > 0) {
                // 已被关注
                returnMsg.setError(ErrorCodeConstants.ERR_1003);
            } else {
                boolean flag = storeManSubProductDaoService.subscribeProduct(staffId, productId, productName);
                if (!flag) {
                    // 关注商品失败
                    returnMsg.setError(ErrorCodeConstants.ERR_1001);
                }
            }
        } else {
            // 该店员已经达到关注上限
            returnMsg.setError(ErrorCodeConstants.ERR_1002);
        }
        
        return returnMsg;
    }

    @Override
    public ReturnMsg<String> unSubscribleProduct(String staffId, String productId) {
        ReturnMsg<String> returnMsg = new ReturnMsg<String>();
        boolean flag = storeManSubProductDaoService.unSubscribeProduct(staffId, productId);
        if (!flag) {
            // 取消商品关注失败
            returnMsg.setError(ErrorCodeConstants.ERR_1004);
        }
        return returnMsg;
    }

    @Override
    public ReturnMsg<List<StoreManSubProduct>> getMySubscribleProducts(String staffId) {
        ReturnMsg<List<StoreManSubProduct>> returnMsg = new ReturnMsg<List<StoreManSubProduct>>();
        List<StoreManSubProduct> list = 
                storeManSubProductDaoService.getSubProductList(staffId);
        returnMsg.setData(list);
        return returnMsg;
    }

    @Override
    public ReturnMsg<ComparePriceResult> getProductSitePrices(String staffId, String productId) {
        ReturnMsg<ComparePriceResult> returnMsg = new ReturnMsg<ComparePriceResult>();
        if (StringUtils.isBlank(productId)) {
            // 校验商品编码不能为空
            returnMsg.setError(ErrorCodeConstants.ERR_0001);
            return returnMsg;
        }
        ComparePriceResult priceResult = new ComparePriceResult();
        // 查询DB确认此商品是否被此员工关注
        int num = storeManSubProductDaoService.countMySubProducts(staffId, productId);
        priceResult.setSubscribe(num > 0 ? true : false);
        // 取站点价格列表
        List<String> productIdList = new ArrayList<String>();
        productIdList.add(productId);
        // 调用CAS价格服务取竞争站点价格信息
        CasProductPrice productPrice =
                casGetProductPriceService.getProductPrice(null, productIdList, false);
        List<ProductPriceBean> prices = getProductPrices(productPrice);
        // 取竞争对手站点自营、上架、有库存、非促销的价格信息
        // 如果同一站点同一商品依旧存在多种价格，则取最低价
        if (CollectionUtils.isNotEmpty(prices)) {
            Map<String, Double> priceMap = new HashMap<String, Double>();
            for (ProductPriceBean bean : prices) {
                // 取自营、上架的价格
                if (ProductPriceBean.Constant.SELF_SELL.equals(bean.getScFlag())
                        && ProductPriceBean.Constant.SELLING.equals(bean.getSellFlag())) {
                    // 比较最低价
                    Double price = priceMap.get(bean.getSiteId());
                    Double tmpPrice = 0.0;
                    if (StringUtils.isNotBlank(bean.getPrice())) {
                        tmpPrice = Double.valueOf(bean.getPrice());
                    }
                    if (null == price) {
                        // 该站点尚未放入价格,将此价格置入map
                        priceMap.put(bean.getSiteId(), tmpPrice);
                    } else {
                        if (price > tmpPrice) {
                            // 原有map中站点价格高于此价格，则替换map中价格
                            priceMap.put(bean.getSiteId(), tmpPrice);
                        }
                    }
                }
            }
            // 组装给客户端返回的数据
            Set<Entry<String, Double>> entries = priceMap.entrySet();
            List<SiteInfo> siteList = new ArrayList<SiteInfo>();
            for (Entry<String, Double> entry : entries) {
                SiteInfo info = new SiteInfo();
                info.setSiteId(entry.getKey());
                info.setSiteName(SITES.get(entry.getKey()));
                // 从zookeeper中取站点logo地址，规则：siteLogo_站点ID
                info.setSiteLogoUrl(ConfigUtil.getConfig("/config/sawp/siteLogo", "siteLogo_" + entry.getKey()));
                // 站点价格
                info.setSitePrice(DF.format(entry.getValue()));
                siteList.add(info);
            }
            priceResult.setSiteList(siteList);
        }
        returnMsg.setData(priceResult);
        
        return returnMsg;
    }

    /**
     * 
     * 功能描述: 取CAS比价接口返回的站点价格列表信息<br>
     * 〈功能详细描述〉
     *
     * @param productPrice
     * @return
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    private List<ProductPriceBean> getProductPrices(CasProductPrice productPrice) {
        List<ProductPriceBean> list = null;
        if (null != productPrice && productPrice.isSuccess()) {
            List<ProductMatchBean> matchProducts = productPrice.getProductMatchBeanList();
            // CAS比价服务接口调用成功
            if (CAS_SUCCESS_CODE.equals(productPrice.getReturnCode())
                    || CollectionUtils.isNotEmpty(matchProducts)) {
                ProductMatchBean matchBean = matchProducts.get(0);
                list = matchBean.getProductPriceBeanList();
            }
        }
        
        return list;
    }
    
    @Override
    public ReturnMsg<List<SiteHistoryPrice>> getProductSiteHistoryPrices(String productId) {
        ReturnMsg<List<SiteHistoryPrice>> returnMsg = new ReturnMsg<List<SiteHistoryPrice>>();
        // 调用CAS价格服务取竞争站点历史价格信息
        LOGGER.info("比价获取近一个月历史价格，查询商品编码: {}", productId);
        List<String> productIdList = new ArrayList<String>();
        productIdList.add(productId);
        CasProductPrice productPrice =
                casGetProductPriceService.getProductPrice(null, productIdList, true);
        List<ProductPriceBean> prices = getProductPrices(productPrice);
        // 取竞争对手站点自营、上架、有库存、非促销的价格信息
        // 如果同一站点同一商品依旧存在多种价格，则取最低价，再取此列价格的历史价格信息
        // 历史价格信息中可能存在日期的断层，需要做补充，不存在价格的日期以-1填充；同时存在一日内存在多个价格的情况，比较之取最低价
        if (CollectionUtils.isNotEmpty(prices)) {
            LOGGER.info("纵向比较，取出每一家站点的最低价begin");
            Map<String, Double> priceMap = new HashMap<String, Double>();
            Map<String, ProductPriceBean> historyPriceMap = new HashMap<String, ProductPriceBean>();
            for (ProductPriceBean bean : prices) {
                // 取自营、上架、有库存、非促销的价格
                if (ProductPriceBean.Constant.SELF_SELL.equals(bean.getScFlag())
                        && ProductPriceBean.Constant.SELLING.equals(bean.getSellFlag())
                        && ProductPriceBean.Constant.IN_STOCK.equals(bean.getStoreFlag())
                        && ProductPriceBean.Constant.NO_PROMOTION.equals(bean.getPromotionFlag())) {
                    // 比较最低价
                    Double price = priceMap.get(bean.getSiteId());
                    if (null == price) {
                        // 该站点尚未放入价格,将此价格置入map
                        priceMap.put(bean.getSiteId(), Double.valueOf(bean.getPrice()));
                        historyPriceMap.put(bean.getSiteId(), bean);
                    } else {
                        if (price > Double.valueOf(bean.getPrice())) {
                            // 原有map中站点价格高于此价格，则替换map中价格
                            priceMap.put(bean.getSiteId(), Double.valueOf(bean.getPrice()));
                            historyPriceMap.put(bean.getSiteId(), bean);
                        }
                    }
                }
            }
            LOGGER.info("纵向比较，取出每一家站点的最低价END");
            
            // 对于过滤后的各家站点所对应的历史价格做处理
            LOGGER.info("开始提取每一家站点近一个月的历史价格数据");
            List<SiteHistoryPrice> list = new ArrayList<SiteHistoryPrice>();
            Set<Entry<String, ProductPriceBean>> entries = historyPriceMap.entrySet();
            for (Entry<String, ProductPriceBean> entry : entries) {
                SiteHistoryPrice historyPrice = new SiteHistoryPrice();
                // 站点ID
                historyPrice.setSiteId(entry.getKey());
                // 站点名称
                historyPrice.setSiteName(SITES.get(entry.getKey()));
                // 历史价格
                historyPrice.setPriceHistory(dealSingleHistoryPirce(entry.getValue()));
                list.add(historyPrice);
            }
            returnMsg.setData(list);
            LOGGER.info("提取每一家站点近一个月的历史价格数据结束");
        }
        LOGGER.info("商品编码: {}, 比价获取近一个月历史价格结束", productId);
        return returnMsg;
    }

    /**
     * 
     * 功能描述: 取当前日期前30天空的价格日历（包含今日）<br>
     * 〈功能详细描述〉
     * 返回日期正序排列
     * @param dateStr yyyyMMdd
     * @return yyyyMMdd, -1 -1 表示当天价格不存在
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    private static Map<String, Double> getLast30DayPriceMap(String dateStr) {
        Map<String, Double> daysPriceMap = new TreeMap<String, Double>();
        SimpleDateFormat sdf = new SimpleDateFormat(DateUtils.YYYYMMDD_PATTERN);
        Calendar c = Calendar.getInstance();
        Date currentTime = null;
        try {
            currentTime = sdf.parse(dateStr);
        } catch (ParseException e) {
            LOGGER.error("getLast30DayPriceMap转换日期失败", e);
            // 如果转换日期失败，则以当前日期为准
            currentTime = new Date();
        }
        for (int i = -29; i < 1; i++) {
            c.setTime(currentTime);
            c.add(Calendar.DAY_OF_MONTH, i);
            daysPriceMap.put(sdf.format(c.getTime()), new Double(-1));
        }
        return daysPriceMap;
    }
    
    /**
     * 
     * 功能描述: 处理单个站点的历史价格数据<br>
     * 〈功能详细描述〉
     * 如果某天价格不存在记作-1，如果一天内存在多个价格，比较给出最低价
     * @param daysList 日历日期列表
     * @param priceBean 单个站点价格数据
     * @return 历史价格日历
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    private List<DatePrice> dealSingleHistoryPirce(ProductPriceBean priceBean) {
        // 获取前30天（包含今天）的空价格日历
        Map<String, Double> historyPriceMap = getLast30DayPriceMap(priceBean.getDateStr());
        SimpleDateFormat sdf = new SimpleDateFormat(DateUtils.YYYYMMDD_PATTERN);
        // 历史价格是否是有序的， 能否保证价格日历在近30天内之内
        // CAS返回历史价格格式，多个价格以空格隔开，时间戳,价格  同一天内可能存在多个价格
        // 1438361222000,119 1438576266000,118 1438622890000,119
        String historyPrice = priceBean.getHistoryPrice();
        if (StringUtils.isNotBlank(historyPrice)) {
            // 存在历史价格
            String[] dayPrices = historyPrice.split(" ");
            for (String dayPrice : dayPrices) {
                String[] args = dayPrice.split(",");
                String date = sdf.format(new Date(Long.parseLong(args[0])));
                Double price = Double.valueOf(args[1]);
                if (historyPriceMap.get(date) < 0) {
                    // 该日的价格尚无，直接替换掉
                    historyPriceMap.put(date, price);
                } else {
                    if (historyPriceMap.get(date) > price) {
                        // 该日的价格日历中已有价格高于price，则以price替换掉
                        historyPriceMap.put(date, price);
                    }
                }
            }
        }
        // 设置今日价格
        // cas 返回报文的historyPrice字段里面不排除已经存在今日的价格，所以判断历史价格日历里面是否存在较大的今日价格
        // 也可能尚无今日价格，这两种情况都需要用price替换掉
        if (historyPriceMap.get(priceBean.getDateStr()) > Double.valueOf(priceBean.getPrice())
                || historyPriceMap.get(priceBean.getDateStr()) < 0) {
            historyPriceMap.put(priceBean.getDateStr(), Double.valueOf(priceBean.getPrice()));
        }
        
        List<DatePrice> priceList = new ArrayList<DatePrice>();
        Set<Entry<String, Double>> entries = historyPriceMap.entrySet();
        for (Entry<String, Double> entry : entries) {
            priceList.add(new DatePrice(entry.getKey(), DF.format(entry.getValue())));
        }
        
        return priceList;
    }
    
}
